/*
 * Ball.cpp
 *
 *  Created on: Nov 18, 2010
 *      Author: timmeh
 */
#include <iostream>
#include "Ball.h"
#include <cmath>
#include "Paddle.h"

using namespace std;

namespace bo {

Ball::Ball() {

}

Ball::~Ball() {

}

/**
 * Makes the ball bounce off another entity and resets the position when they're penetrating
 */
void Ball::Bounce(Entity* ent){
	// Fixes ball when it "penetrates" another ball.
	double angle = std::atan2(ent->GetPos().GetY() - fPos.GetY(),
								ent->GetPos().GetX() - fPos.GetX());
	double circDist = sqrt(pow(ent->GetPos().GetX() - fPos.GetX(), 2) +
							pow(ent->GetPos().GetY() - fPos.GetY(), 2));
	double toMove = fRadius + ent->GetRadius() - circDist;
	fPos.SetX(fPos.GetX() + std::cos(angle) * toMove);
	fPos.SetY(fPos.GetY() + std::cos(angle) * toMove);
	// Uit cursus GFX:
	
	//Vector perpendicular to the vector between the 2 centers
	Vector2 tangentVector(ent->GetPos().GetY() - fPos.GetY(),
								-( ent->GetPos().GetX() - fPos.GetX() ) );
	tangentVector.Normalize();
	// The (normal)vector between the 2 centers
	Vector2 normalVect(ent->GetPos().GetX() - fPos.GetX(), ent->GetPos().GetY() - fPos.GetY());
	normalVect.Normalize();
	// Vectorise the velocity
	Vector2 velVect(this->fXVel, this->fYVel);
	double norm = velVect.Norm(); // Save original norm so I can restore the speed of the ball later.
	velVect.Normalize();
	// Dotproduct between the velocityvector and the normalvector
	double alpha = velVect.DotProd(normalVect);
	// Reflection vector (credits: Graphics, 1st year)
	Vector2 refVector = normalVect * 2 * std::cos(alpha) - velVect;
	// Normalise and "reset" the velocity to its original speed
	refVector.Normalize();
	this->fXVel = -refVector.GetX() * norm;
	this->fYVel = -refVector.GetY() * norm;
}

/**
 * Returns the radius of the ball
 */
double Ball::GetRadius(){
	return fRadius;
}

/**
 * Sets the radius of the ball
 */
void Ball::SetRadius(double rad){
	fRadius = rad;
}

/**
 * Returns true if the ball is colliding with the supplied entity
 */
bool Ball::CollidesWith(Entity* ent){
	Vector2 distance = (ent->GetPos() - fPos);
	double length = distance.Length();
	return ( length < (fRadius + ent->GetRadius() ) );
}

/**
 * Returns X component of velocity
 */
double Ball::GetXVelocity(){
	return fXVel;
}

/**
 * Returns Y component of velocity
 */
double Ball::GetYVelocity(){
	return fYVel;
}

/**
 * Sets the initial velocity
 */
void Ball::SetDoubleVelocity(const double xVel, const double yVel){
	fXVel = xVel;
	fYVel = yVel;
}

/**
 * Advances the ball 1 step, according to its velocity
 */

void Ball::AdvanceBall(){
	fPos.SetX(fPos.GetX() + fXVel);
	fPos.SetY(fPos.GetY() + fYVel);
}

/**
 * Returns the position of the ball
 */
Vector2 Ball::GetPos(){
	return fPos;
}

/**
 * Sets the position of the ball
 */

void Ball::SetPos(double xPos, double yPos){
	fPos.SetX(xPos);
	fPos.SetY(yPos);
}

}
